using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Surface.Core;

namespace XnaSurfaceToolKit
{
    public class ContactManager : Microsoft.Xna.Framework.IGameComponent, Microsoft.Xna.Framework.IUpdateable
    {
        private GameWindow win;
        private ContactTarget _contactTarget;
        private ReadOnlyContactCollection _previousContacts;

        public List<Contact> ActualContact { get; protected set; }
        public List<Contact> LostContact { get; protected set; }
        public List<Contact> NewContact { get; protected set; }
        public int Blob { get; protected set; }
        public int Finger { get; protected set; }
        public int Tag { get; protected set; }

        public ContactManager(GameWindow window)
        {
            this.win = window;
        }

        #region IGameComponent Members
        public void Initialize()
        {
            this.ActualContact = new List<Contact>();
            this.LostContact = new List<Contact>();
            this.NewContact = new List<Contact>();
            this.Blob = 0;
            this.Finger = 0;
            this.Tag = 0;

            this._contactTarget = new ContactTarget(this.win.Handle, EventThreadChoice.OnBackgroundThread);
            this._contactTarget.EnableInput();
        }
        #endregion
        public void Update(GameTime gameTime)
        {
            this.UpdateContact();
        }
        private void UpdateContact()
        {
            ReadOnlyContactCollection currentContacts = _contactTarget.GetState();
            Contact tempContact = null;

            this.LostContact.Clear();
            this.NewContact.Clear();

            if (_previousContacts != null)
            {
                foreach (Contact contact in _previousContacts)
                {
                    if (!currentContacts.TryGetContactFromId(contact.Id, out tempContact))
                    {
                        // Contact removed
                        this.RemoveContact(contact);
                    }
                }
            }
            foreach (Contact contact in currentContacts)
            {
                if (!_previousContacts.TryGetContactFromId(contact.Id, out tempContact))
                {
                    // Contact added
                    this.AddContact(contact);
                }
                else
                {
                    // Contact who was already here, usefull for any action like movement
                    this.RemoveContact(contact);
                    this.AddContact(contact);
                }
            }
            _previousContacts = currentContacts;
        }
        private void AddContact(Contact contact)
        {
            this.NewContact.Add(contact);
            this.ActualContact.Add(contact);
            ManageNB(contact, 1);
        }

        private void ManageNB(Contact contact, int value)
        {
            if (contact.IsFingerRecognized)
                this.Finger += value;
            else
                this.Blob += value;
            if (contact.IsTagRecognized)
                this.Tag += value;
        }
        private void RemoveContact(Contact contact)
        {
            Contact c;

            this.LostContact.Add(contact);
            for (int i = 0; i < this.ActualContact.Count; i++)
            {
                c = this.ActualContact[i];
                if (c.Id == contact.Id)
                    this.ActualContact.Remove(c);
            }
            ManageNB(contact, -1);
        }
        #region IUpdateable Members

        public bool Enabled { get; set; }

        public event EventHandler EnabledChanged;

        public int UpdateOrder { get; set; }

        public event EventHandler UpdateOrderChanged;

        #endregion
    }
}
